use attestation_common::env_config_parse::yaml_parse::YamlValue;
use attestation_common::log::info;
use attestation_common::yaml_get;
use mockall::automock;
use serde::Deserialize;
use std::env;
use std::fmt::Debug;

#[automock]
pub trait ConfigLoader: Debug {
    fn load_config(&self) -> Option<Box<dyn Config>>;
}

#[derive(Debug)]
pub struct YamlConfigLoader;

impl ConfigLoader for YamlConfigLoader {
    fn load_config(&self) -> Option<Box<dyn Config>> {
        let exe_path = env::current_exe().ok()?;
        let exe_dir = exe_path.parent()?;
        // Construct the absolute path of the configuration file
        let config_path = exe_dir
            .parent()? // target/debug -> target
            .parent()? // target -> project root
            .join("server_config.yaml");
        info!("config_path: {}", config_path.to_str().unwrap());
        let yaml = YamlValue::from_file(config_path.to_str().unwrap()).unwrap();
        let get_vault_url = |str: &str| -> Option<YamlConfig> {
            let vault_get_key_url = yaml_get!(yaml.clone(), str => str).unwrap();
            Some(YamlConfig {
                vault_get_key_url: vault_get_key_url.to_string(),
            })
        };
        Some(Box::new(
            get_vault_url("attestation_service.attestation_verifier.vault_get_key_url").unwrap(),
        ))
    }
}

pub trait Config {
    fn vault_get_key_url(&self) -> String;
}

#[derive(Deserialize, Debug, Clone)]
pub struct YamlConfig {
    pub vault_get_key_url: String,
}

impl Config for YamlConfig {
    fn vault_get_key_url(&self) -> String {
        self.vault_get_key_url.clone()
    }
}

#[cfg(test)]
#[allow(warnings)]
mod tests {
    use super::*;
    use attestation_common::env_config_parse::yaml_parse::YamlValue;
    use mockall::predicate::*;
    use std::path::PathBuf;
    use tempfile::TempDir;
    use crate::config;

    // 测试模拟的配置路径处理
    #[test]
    fn test_config_loader_path_resolution() {
        let current_exe = env::current_exe().ok().unwrap();
        let yml_dir = current_exe.parent().unwrap().parent().unwrap().parent().unwrap();
        // 创建临时目录结构模拟项目布局
        std::fs::create_dir_all(&yml_dir).unwrap();

        // 创建模拟配置文件
        let config_content = r#"
        attestation_service:
          attestation_verifier:
            vault_get_key_url: "https://mock.vault.com/api"
        "#;
        std::fs::write(yml_dir.join("server_config.yaml"), config_content).unwrap();

        // 设置当前可执行文件路径环境
        let loader = YamlConfigLoader;

        // 验证配置加载0
        let config = loader.load_config().expect("Should load config");
        assert_eq!(
            config.vault_get_key_url(),
            "https://mock.vault.com/api"
        );
    }

    // 测试YamlConfig结构体的功能
    #[test]
    fn test_yaml_config_implementation() {
        let yaml_config = YamlConfig {
            vault_get_key_url: "https://test.url".to_string()
        };
        let config: &dyn Config = &yaml_config;
        assert_eq!(config.vault_get_key_url(), "https://test.url");
    }

    // 使用mock测试ConfigLoader trait
    #[test]
    fn test_mock_config_loader() {
        let mut mock_loader = MockConfigLoader::new();

        // 设置mock期望
        mock_loader.expect_load_config()
            .returning(|| Some(Box::new(YamlConfig {
                vault_get_key_url: "mock://test.url".to_string()
            })));

        // 验证mock行为
        let config = mock_loader.load_config().unwrap();
        assert_eq!(config.vault_get_key_url(), "mock://test.url");
    }
}
